/*
    Copyright 2006-2011 Patrik Jonsson, sunrise@familjenjonsson.org

    This file is part of Sunrise.

    Sunrise is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    Sunrise is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Sunrise.  If not, see <http://www.gnu.org/licenses/>.

*/

/** \file

    Implementations of the FITS-related emergence functions. These are
    kept in a separate file to avoid always having to include the
    CCfits headers. */

#ifndef __emergence_fits__
#define __emergence_fits__

#include "emergence.h"
#include "CCfits/CCfits"
#include <sstream> 
#include "blitz-fits.h"
#include "mpi_util.h"

/** Constructs an emergence object from (possibly a selection of) the
    CAMERAi-PARAMETER HDU's in a FITS file. */
template <typename T_image>
mcrx::emergence<T_image>::emergence (const CCfits::FITS& file)
{
  int i = 0;
  try {
    while (true) {
      std::ostringstream ost;
      ost << "CAMERA" << i << "-PARAMETERS";
      // this will throw when we get to a camera that doesn't exist
      const CCfits::ExtHDU* hdu;
      try {
	hdu = &file.extension(ost.str() );
      }
      catch (CCfits::FITS::NoSuchHDU&) {
	const_cast<CCfits::FITS&> (file).read(string (ost.str()));
	hdu = &file.extension(ost.str() );
      }

      // read camera keywords (ideally, this would be done by a camera
      // constructor, but because they are const members and there is no
      // suitable CCfits function to return a keyword value, we have to
      // do it like this...)
      float cameradist;
      int xs, ys;

      CCfits::ExtHDU& silly = const_cast<CCfits::ExtHDU&> (*hdu);

      boost::shared_ptr<projection> proj = projection::read_projection(silly);

      silly.readKey("cameradist", cameradist);
      silly.readKey("ysize", ys);
      silly.readKey("xsize", xs );

      vec3d pos,dir,ny;
      silly.readKey("camposx",pos[0]);
      silly.readKey("camposy",pos[1]);
      silly.readKey("camposz",pos[2]);
      silly.readKey("camdirx", dir [0]);
      silly.readKey("camdiry", dir [1]);
      silly.readKey("camdirz", dir [2]);
      silly.readKey("camupx", ny [0]);
      silly.readKey("camupy", ny [1]);
      silly.readKey("camupz", ny [2]);
      cameras.push_back(new T_camera (pos, dir, ny, ys, proj));

      ++i;
    }
  }
  catch (CCfits::FITS::NoSuchHDU&) {} 
}  

/** Writes camera parameters and the pixel solid angle image to a FITS
    file. \todo We may need to subsample the solid angle to get it
    right i.e. for the Aitoff where it cuts off sharply at the edge of
    the valid area.  */
template <typename T_image>
void mcrx::emergence<T_image>::write_parameters (CCfits::FITS& file,
						 const T_unit_map& units) const
{
  if(!is_mpi_master())
    return;

  // Loop over cameras and write parameters for each

  for (int c=0; c< n_cameras(); ++c) {

    const T_camera& cam = get_camera (c);

    std::ostringstream ost;
    ost << "CAMERA" << c << "-PARAMETERS";
    
    cout << ost.str()<< endl;

    // check if HDU already exists
    CCfits::ExtHDU* hdu;    
    try {
      hdu = &open_HDU (file, ost.str ());
      // it would probably be good to check that image dimensions are
      // consistent
    }
    catch (CCfits::FITS::NoSuchHDU&) {
      std::vector<long> naxes;
      naxes.push_back(cam.xsize());
      naxes.push_back(cam.ysize());
      hdu = file.addImage (ost.str(), FLOAT_IMG, naxes);
      file.setCompressionType(0);

      hdu->writeComment("This HDU contains the camera parameters. The image contains the solid angle subtended by the individual pixels.");
    }
    cam.write_parameters(*hdu, units);

    // Create the solid angle image.
    array_2 pixel_sr= cam.pixel_solid_angle_image();
    write(*hdu, pixel_sr);
  }
}

#endif

